#pragma once

#include<iostream>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"Err.hpp"
#include"Log.hpp"

static const int gbacklog = 32;
static const int defaultfd = -1;

//适配服务端和客户端
class Sock
{
public:
    Sock():_sock(-1)
    {}
    //创建套接字
    void Socket()
    {
        _sock=socket(AF_INET,SOCK_STREAM,0);
        if(_sock<0)
        {
            logMessage(Fatal,"socket error,code:%d,errstring:%s",errno,strerror(errno));
            exit(SOCKET_ERR);
        }
    }

    //绑定套接字
    void Bind(uint16_t &port)
    {   
        struct sockaddr_in server;
        server.sin_family=AF_INET;
        server.sin_port=htons(port);
        server.sin_addr.s_addr=INADDR_ANY;

        if(bind(_sock,(struct sockaddr*)&server,sizeof(server)))
        {
            logMessage(Fatal,"bind error,code:%d,errstring:%s",errno,strerror(errno));
            exit(BIND_ERR);
        }
    }

    //添加监听
    void Listen()
    {
        if(listen(_sock,gbacklog)<0)
        {
            logMessage(Fatal,"listen error,code:%d,errstring:%s",errno,strerror(errno));
            exit(LISTEN_ERR);
        }
    }

    //接收连接
    int Accept(std::string&clientIp,uint16_t&clientPort)
    {
        struct sockaddr_in client;
        socklen_t len=sizeof(client);
        int sock=accept(_sock,(struct sockaddr*)&client,&len);
        if(sock<0)
        {
            logMessage(Warning,"accept error,code:%d,errstring:%s",errno,strerror(errno));
        }
        else
        {
            clientIp=inet_ntoa(client.sin_addr);
            clientPort=ntohs(client.sin_port);
        }

        return sock;
    }

    //连接
    int Connect(std::string&serverIp,uint16_t&serverPort)
    {
        struct sockaddr_in server;
        server.sin_family=AF_INET;
        server.sin_port=htons(serverPort);
        server.sin_addr.s_addr=inet_addr(serverIp.c_str());

        return connect(_sock,(struct sockaddr*)&server,sizeof(server));
    }

    int Fd()
    {
        return _sock;
    }

    void Close()
    {
        if(_sock!=defaultfd)
            close(_sock);
    }

    ~Sock()
    {
        
    }
private:
    int _sock;//套接字
};